package com.powernode.dispatch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.powernode.common.constant.RedisConstant;
import com.powernode.common.result.Result;
import com.powernode.dispatch.client.XxlJobClient;
import com.powernode.dispatch.mapper.OrderJobMapper;
import com.powernode.dispatch.service.NewOrderService;
import com.powernode.map.client.LocationFeignClient;
import com.powernode.model.entity.dispatch.OrderJob;
import com.powernode.model.enums.OrderStatus;
import com.powernode.model.form.map.SearchNearByDriverForm;
import com.powernode.model.vo.dispatch.NewOrderTaskVo;
import com.powernode.model.vo.map.NearByDriverVo;
import com.powernode.model.vo.order.NewOrderDataVo;
import com.powernode.order.client.OrderInfoFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 新订单服务实现类
 * 负责处理新订单相关的业务逻辑，包括添加启动订单任务、查询新订单队列数据等功能
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {
    @Resource
    private OrderJobMapper orderJobMapper; // 自动注入OrderJobMapper，用于操作订单任务数据库
    @Resource
    private XxlJobClient xxlJobClient; // 自动注入XxlJobClient，用于操作XXL-Job调度任务
    @Resource
    private LocationFeignClient locationFeignClient; // 自动注入LocationFeignClient，用于操作地图服务
    @Resource
    private OrderInfoFeignClient orderInfoFeignClient; // 自动注入OrderInfoFeignClient，用于操作订单服务
    @Resource
    private RedisTemplate redisTemplate; // 自动注入RedisTemplate，用于操作Redis数据库
    @Autowired
    private RestTemplate restTemplate; // 自动注入RestTemplate，用于发送HTTP请求

    /**
     * 添加并启动新订单任务
     *
     * @param newOrderTaskVo 新订单任务参数对象，包含订单ID等信息
     * @return 任务ID，唯一标识已添加的调度任务
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        // 创建条件查询包装器
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：订单ID等于传入的订单ID
        queryWrapper.eq(OrderJob::getOrderId, newOrderTaskVo.getOrderId());
        // 根据条件查询订单任务
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);

        // 判断是否已存在该订单的任务，如果不存在则创建新任务
        if (orderJob == null) {
            // 调用XXL-Job客户端添加并启动任务
            // 参数1：执行器处理器名称（newOrderTaskHandler）
            // 参数2：执行参数（这里为空字符串）
            // 参数3：Cron表达式（表示每分钟执行一次）
            // 参数4：任务描述（包含订单ID）
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "", "0 0/1 * * * ?", "用户下单：" + newOrderTaskVo.getOrderId());

            // 创建新的订单任务实体对象
            orderJob = new OrderJob();
            orderJob.setJobId(jobId);  // 设置任务ID
            orderJob.setOrderId(newOrderTaskVo.getOrderId());  // 设置订单ID
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));  // 将任务参数对象转换为JSON字符串存储

            // 将订单任务信息插入到数据库
            orderJobMapper.insert(orderJob);
        }
        // 返回订单任务的任务ID
        return orderJob.getJobId();
    }

    /**
     * 执行订单任务
     * 1.查询任务参数
     * 2.查询订单状态
     * 3.搜索附近配送员
     * 4.给配送员派单
     *
     * @param jobId 任务ID
     * @return 执行结果，成功返回true
     */
    @Override
    public Boolean executeTask(Long jobId) {
        // 创建条件查询包装器，用于查询订单任务
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：任务ID等于传入的任务ID
        queryWrapper.eq(OrderJob::getJobId, jobId);
        // 根据条件查询订单任务信息
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        // 将存储在任务参数中的JSON字符串解析为NewOrderTaskVo对象
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);

        // 调用订单服务Feign客户端查询订单当前状态
        Integer orderStatus = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId()).getData();
        // 检查订单状态是否不是待接单状态
        if (orderStatus.intValue() != OrderStatus.WAITING_ACCEPT.getStatus().intValue()) {
            // 如果订单状态不是待接单，停止当前任务
            xxlJobClient.stopJob(jobId);
            return true;
        }

        // 创建搜索附近配送员的表单对象
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        // 设置起点纬度
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        // 设置起点经度
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        // 设置期望距离（用于过滤附近配送员）
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());
        // 调用位置服务Feign客户端搜索附近的配送员
        List<NearByDriverVo> nearByDriverVoList = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();

        // 遍历附近的配送员列表
        nearByDriverVoList.forEach(driver -> {
            // 构建配送员订单重复列表的Redis键
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST + newOrderTaskVo.getOrderId();
            // 检查配送员是否已经在重复列表中（避免重复派单）
            Boolean isMember = redisTemplate.opsForSet().isMember(repeatKey, driver.getDriverId());

            // 如果配送员不在重复列表中
            if (!isMember) {
                // 将配送员添加到重复列表中
                redisTemplate.opsForSet().add(repeatKey, driver.getDriverId());
                // 设置重复列表的过期时间
                redisTemplate.expire(repeatKey, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);

                // 创建新订单数据对象
                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                // 将NewOrderTaskVo的属性复制到NewOrderDataVo中
                BeanUtils.copyProperties(newOrderTaskVo, newOrderDataVo);

                // 构建配送员订单临时列表的Redis键
                String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                // 将订单数据添加到配送员的临时订单列表的左侧（队列）
                redisTemplate.opsForList().leftPush(key, newOrderDataVo);
                // 设置临时订单列表的过期时间
                redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
            }
        });
        // 返回执行成功
        return true;
    }

    /**
     * 查询指定配送员的新订单队列数据
     * 配送员查询redis中派单信息
     * 配送员可能收到多个订单
     *
     * @param driverId 配送员ID
     * @return 新订单数据列表
     * @apiNote 该方法目前返回空列表，尚未实现实际查询逻辑
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        // 初始化新订单数据列表，用于存储查询结果
        ArrayList<NewOrderDataVo> arrayList = new ArrayList<>();
        // 构建Redis中配送员临时订单列表的Key（格式：DRIVER_ORDER_TEMP_LIST + 配送员ID）
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        // 获取Redis列表中订单数据的数量
        Long size = redisTemplate.opsForList().size(key);

        // 判断列表中是否存在订单数据
        if (size > 0) {
            // 循环获取列表中的所有订单数据（FIFO方式，从左侧弹出）
            for (int i = 0; i < size; i++) {
                // 从Redis列表左侧弹出一个订单数据（弹出后该数据从列表中移除）
                String content = (String) redisTemplate.opsForList().leftPop(key);
                // 将JSON字符串解析为NewOrderDataVo对象
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);
                // 将解析后的订单数据添加到结果列表
                arrayList.add(newOrderDataVo);
            }
        }
        // 返回包含所有订单数据的列表
        return arrayList;  // 返回空列表
    }

    /**
     * 清除指定配送员的新订单队列数据
     *
     * @param driverId 配送员ID
     * @return 操作结果，成功返回true
     * @apiNote 该方法目前返回null，尚未实现实际清除逻辑
     */
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        // 构建Redis中配送员临时订单列表的Key（格式：DRIVER_ORDER_TEMP_LIST + 配送员ID）
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        // 删除Redis中对应的订单队列数据（清除整个列表）
        redisTemplate.delete(key);
        // 返回null（注：实际业务中建议返回删除操作是否成功的布尔值）
        return null;  // 返回null
    }
}
